/*!	文档说明：
 *	说明：jQuery文件Ajax上传插件，不支持Ajax上传的浏览器将使用iframe技术替代。
 *	作者：屈金辉
 *	版本：1.0
 *	编写日期：2013年6月24日
 *	最后修改：2013年8月5日
 */




;(function( $, window, undefined ) {

var
	document = window.document,

	// 默认参数
	defaults = {
		autoUpload : true,				// 选择文件后是否自动开始上传，默认自动开始上传
		usePreview : true,				// 是否启用图片预览功能，默认启用
		infoContainer : "",				// 用于显示上传文件提示信息的容器ID，如果为空，将在当前上传按钮下方显示
		preWidth : 200,					// 图片预览的最大宽度
		preHeight : 120,				// 图片预览的最大高度
		handler : "uploader.php",		// 处理文件上传的服务端程序路径
		fileType : "*",					// 可用的文件类型，以|为分隔符，例如："jpg|png|gif"，*表示不限制
		maxSize : 1024 * 1024 * 2		// 文件最大限制，单位：字节，默认2M，如果设为0则不限制
	},

	// 构造函数
	Uploader = function ( file, config ) {
		this.id = ++Uploader.prototype.counter;				// 创建当前实例编号
		this.file = file;
		this.$infoWrap = null;
		this.init( config );
	};

Uploader.prototype = {

	// 修复构造函数的引用
	constructor : Uploader,

	// 实例计数器
	counter: 0,

	// 初始化方法
	init : function ( config ) {
		if ( $(this.file).parent().triggerHandler( "select.uploader", [ this.file, this ] ) === false ) return this;

		this.setFileInfo();
		this.initConfig( config );
		if ( !this.isAllowType() ) return this.showError( "文件类型不可用，仅支持：" + this.cfg.fileType + " 类型！" );
		var ret = this.isAllowSize();
		if ( !ret ) return typeof ret !== "undefined" && this.showError( "文件大小不可超过" + this.cfg.maxSize / 1024 / 1024 + "M！" );

		this.createInfo();
		this.createPreview();
		this.cfg.autoUpload && this.upload();
	},

	// 初始化配置参数
	initConfig : function ( config ) {

		// 如果配置参数已存在，绑定参数并返回当前对象
		if ( this.file.$$_upload_cfg ) {
			this.cfg = this.file.$$_upload_cfg;
			return this;
		}
		
		// 获取与合并配置参数
		var $cfgWrap = $( this.file ).parent(),
		val = $cfgWrap.attr( "data-upload-config" ),
		custom = config || ( val && val.charAt(0) == "{" && eval("(" + val + ")") ) || {},
		cfg = $.extend( true, {}, defaults, custom );

		// 如果上传控件包装容器额外设置data-upload-url(上传地址)参数，将其覆盖到配置参数的handler
		$cfgWrap.attr( "data-upload-url" ) && ( cfg.handler = $cfgWrap.attr("data-upload-url") );

		this.file.$$_upload_cfg = this.cfg = cfg;
	},

	// 开始上传方法
	upload : function () {
		// 禁用上传按钮
		$( this.file ).parent().addClass("disabled");
		this.file.style.visibility = "hidden";

		this.$infoWrap.find("h4 span.result-tips").html( "" );	// 清空上传结果提示文本
		this.$infoWrap.find("i span.progress").css( "visibility", "visible" );		// 显示进度提示
		if ( window.XMLHttpRequest && new XMLHttpRequest().upload ) {
			this.ajaxUpload();
		} else {
			this.iframeUpload();
		}
	},

	// Ajax上传方案
	ajaxUpload : function () {
		var $imgWrap = this.$infoWrap.find("i");
		$imgWrap.find("span.progress").html( "0%" );
		var hasForm = $( this.file ).parents( "#uploader-form-" + this.id ).length > 0;

		!hasForm && $( this.file ).parent().wrap( '<form id="uploader-form-' + this.id + '" name="uploader-form-' + this.id + '" enctype="multipart/form-data"></form>' );
		var fd = new FormData( $( "#uploader-form-" + this.id )[0] );
		var xhr = new XMLHttpRequest();
        xhr.upload.addEventListener( "progress", $.proxy( this.progress, this, $imgWrap.find(".progress") ), false );
        xhr.addEventListener( "error", $.proxy( this.error, this ), false );
        xhr.addEventListener( "load", $.proxy( this.complete, this ), false );
        xhr.open( "POST", this.cfg.handler );
        xhr.send( fd );
	},

	// iframe上传方案
	iframeUpload : function () {
		var _this = this,
		$imgWrap = this.$infoWrap.find("i");
		$iframe = $( '<iframe class="uploader-iframe" name="uploader-iframe-' + this.id + '"></iframe>' );
		$imgWrap.find("span.progress").html( '<i class="ui-uploader-icon-loading"></i>' );
		$( "body" ).append( $iframe );
		$iframe.load( function (){
			_this.complete( { target : { responseText: $(this).contents().text() } } );
			$( this ).remove();		// 删除当前iframe
		} );

		var hasForm = $( this.file ).parents( "#uploader-form-" + this.id ).length > 0;
		!hasForm && $( this.file ).parent().wrap( '<form id="uploader-form-' + this.id + '" name="uploader-form-' + this.id + 
			'" target="uploader-iframe-' + this.id + '" action="' + this.cfg.handler + '" method="post" enctype="multipart/form-data"></form>' );
		$( "#uploader-form-" + this.id ).submit();
	},

	// 创建上传文件提示信息
	createInfo : function () {
		var html = 
			'<div id="uploader-info-' + this.id + '" class="ui-uploader-info-wrapper">\
				<h4>文件名: ' + this.file.fileName + '<span class="result-tips"></span></h4>\
				<i style="width:' + this.cfg.preWidth + 'px;height:' + this.cfg.preHeight + 'px;"><span class="progress"></span></i>\
			</div>';
		
		if ( this.cfg.infoContainer !== "" ) {
			$( "#" + this.cfg.infoContainer ).html( html );
		} else {
			this.$infoWrap ? this.$infoWrap.replaceWith( html ) : $( this.file ).parent().after( html );
		}

		// 绑定上传文件信息元素的jQuery包装对象
		this.$infoWrap = $( "#uploader-info-" + this.id );

		// 如果非选择后自动上传，为文件提示信息的容器添加一个开始上传按钮
		if ( !this.cfg.autoUpload ) {
			var _this = this;
			this.$btnStart = $( '<span class="ui-start-upload-btn">开始上传</span>' );
			this.$btnStart.click(function () {
				$(this).hide();
				_this.upload();
			});
			this.$infoWrap.append( this.$btnStart );
		}
	},

	// 创建选中图片文件的预览
	createPreview : function () {
		// 如果非图片文件，使用文件扩展名代替图片
		if ( !this.cfg.usePreview || this.file.fileType.search(/png|jpe?g|gif|bmp/i) < 0 ) {
			this.$infoWrap.find("i").append( '<strong style="line-height:' + this.cfg.preHeight + 'px;">' + this.file.fileType + '</strong>' );
			return this;
		}

		var _this = this,
			$imgWrap = this.$infoWrap.find("i"),
			src = "";

		if ( typeof FileReader !== "undefined" ) {
			var reader = new FileReader();
			reader.onload = function(e){
				$imgWrap.append( '<img width="' + _this.cfg.preWidth + '" height="' + 
					_this.cfg.preHeight + '" src="' + this.result + '" />' );
			}
			reader.readAsDataURL(this.file.files[0]);
		} else {
			src = this.getSrc();
			if ( !src ) {
				this.$infoWrap.find("i").append( '<strong style="line-height:' + this.cfg.preHeight + 'px;">' + this.file.fileType + '</strong>' );
				this.uploadedPreview = true;		// 上传取回图片预览
				return this;
			}

			if ( this.file.files ) {
				$imgWrap.append( '<img width="' + this.cfg.preWidth + '" height="' + 
					this.cfg.preHeight + '" src="' + src + '" />' );
			} else if ( $imgWrap[0].filters ) {
            	$imgWrap.css( { width : this.cfg.preWidth, height : this.cfg.preHeight } );

				try {
					$imgWrap[0].style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=scale)";
					$imgWrap[0].filters.item( "DXImageTransform.Microsoft.AlphaImageLoader" ).src = src;
				} catch (e) {
					this.showError( "图片格式不正确！" );
				}
			}
		}
	},

	// 获取图片资源路径
	getSrc : function () {
		if ( window.URL && window.URL.createObjectURL ) {
			return window.URL.createObjectURL( this.file.files[0] );
		} else if  ( window.webkitURL && window.webkitURL.createObjectURL ) {
			return window.webkitURL.createObjectURL( this.file.files[0] );
		} else if ( this.file.files && this.file.files[0].getAsDataURL ) {
			return this.file.files[0].getAsDataURL();
		} else if ( this.file.filters ) {
			// this.file.select();
			// var src = document.selection.createRange().text;
			// document.selection.empty();
			// return src;
			return this.file.value;
		}

		return null;
	},

	// 检测选中文件的大小是否可用
	isAllowSize : function () {
		if ( this.cfg.maxSize === 0 ) return true;
		if ( this.file.files && this.file.files[0].size !== undefined ) {
			if ( this.file.files[0].size > this.cfg.maxSize ) return false;
		} else if ( window.ActiveXObject ) {
			try {
				var f = new Image();
				f.dynsrc = this.file.value;
				if ( f.fileSize > this.cfg.maxSize ) return false;
			} catch (e) {
				try {
					var fso = new ActiveXObject("Scripting.FileSystemObject");
					f = fso.getFile(this.file.value);
					if ( f.size > this.cfg.maxSize ) return false;
				} catch (e) {
					this.showError("上传功能需要您启用浏览器对ActiveX控件的支持！");
					return;
				}
			}
		}
		return true;
	},

	// 检测选中文件的类型是否可用
	isAllowType : function () {
		if ( this.cfg.fileType === "*" ) return true;
		var t = this.cfg.fileType.toLowerCase().split( "|" );
		if ( $.inArray( this.file.fileType, t ) === -1 ) return false;
		return true;
	},

	// 设置选中文件的信息
	setFileInfo : function () {
		var t;
		// 设置文件名
		if ( this.file.files && this.file.files[0].name ) {
			this.file.fileName = this.file.files[0].name;
		} else {
			t = this.file.value.split( /\\|\// );
			this.file.fileName = t[ t.length - 1 ];
		}

		// 设置文件类型(扩展名)
		t = this.file.fileName.split( "." );
		this.file.fileType = t[ t.length - 1 ].toLowerCase();
	},

	// 上传进度处理器
	progress : function ( $tips, e ) {
		if ( e.lengthComputable ) {
          var percent = Math.round( e.loaded * 100 / e.total );
          $tips.html( percent.toString() + '%' );
        } else {
          this.showError( "您的浏览器不支持上传进度事件！" );
        }
	},

	// 上传出错处理器
	error : function ( e, res ) {//alert(res);
		// 启用上传按钮
		$( this.file ).parent().removeClass("disabled");
		this.file.style.visibility = "visible";

		!this.cfg.autoUpload && this.$btnStart && this.$btnStart.show();		// 重新显示开始上传按钮
		if ( $(this.file).parent().triggerHandler( "error.uploader", [ res ] ) === false ) return false;
		this.showTips( "文件上传时出错", "error" );
		return true;
	},

	// 上传完成处理器
	complete : function ( e ) {
		// 启用上传按钮
		$( this.file ).parent().removeClass("disabled");
		this.file.style.visibility = "visible";

		try {
			var res = e.target.responseText,
			resJSON = $.parseJSON( $.trim( res ) );
			if ( $(this.file).parent().triggerHandler( "response.uploader", [ res ] ) === false ) return this;
			if ( res === null ) {
				e.type = "error";
				return this.error( e, res );
			}
		} catch ( ex ) {
			e.type = "error";
			return this.error( e, res );
		}

		if ( resJSON.error ) {
			// 服务端返回的JSON数据中存在错误定义
			if ( $(this.file).parent().triggerHandler( "error.uploader", [ res ] ) === false ) return false;
			this.showTips( resJSON.errorTipsMap[ resJSON.error ], "error" );
		} else {
			if ( $(this.file).parent().triggerHandler( "success.uploader", [ res ] ) === false ) return this;
			this.showTips();
			// 如果客户端浏览器不支持上传前浏览图片，则在图片文件上传成功之后取回上传的图片进行预览
			this.uploadedPreview && this.$infoWrap.find("strong").replaceWith( '<img width="' + this.cfg.preWidth + '" height="' + 
				this.cfg.preHeight + '" src="' + res.data.filePath + '" />' );
		}
	},

	// 显示上传处理提示文字
	showTips : function ( msg, type ) {
		msg = msg || "上传成功", type = type || "success";
		type == "error" && ( msg = "错误: " + msg );
		this.$infoWrap.find("h4 span.result-tips").html('<span class="label-' + type + '">' + msg + '</span>');
		this.$infoWrap.find(".progress").html( '<i class="ui-uploader-icon-' + type + '"></i>' );
		return this;
	},

	// 显示错误消息框
	showError : function ( msg ) {
		alert( msg );
	}
}

Uploader.defaults = defaults;

// 插件初始化静态方法
Uploader.init = function () {

	// 动态引入uploader.css样式表文件
	if ( $( "link[href*='uploader.css']" ).length === 0 ) {
		var jsPath = $( "[src*='jquery.xianyu.uploader.']" ).attr( "src" ),
		dir = jsPath.substring( 0, jsPath.indexOf( "jquery.xianyu.uploader." ) );
		$( '<link rel="stylesheet" type="text/css" href="' + dir + 'uploader.css" />' ).appendTo( "head" );
	}

	// 为上传按钮容器绑定file表单控件
	$( ".ui-upload-btn" ).append( '<input name="file" type="file" />' );

	// 为file表单控件绑定事件
	$(document).on("change", ".ui-upload-btn input:file", function () {
		if ( this.$$_uploader ) return this.$$_uploader.init();
		this.$$_uploader = new Uploader(this);
	});
};

// 将插件对象绑定到jQuery命名空间
$.Uploader = Uploader;


$(function () {
	$.Uploader.init();
});


})( jQuery, this );